/*
 * @Author: intellectual-seeker 3336339701@qq.com
 * @Date: 2025-09-03 11:35:16
 * @LastEditors: intellectual-seeker 3336339701@qq.com
 * @LastEditTime: 2025-09-03 11:48:50
 * @FilePath: /code/lesson33/consumer_productor-fix/BlockQueue.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#ifndef BLOCK_QUEUE_HPP
#define BLOCK_QUEUE_HPP

#include <queue>
#include <pthread.h>

template<typename T>
class BlockQueue
{
public:
    BlockQueue(int cap)
    {
        _cap = cap;
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_consumer_cond, nullptr);
        pthread_cond_init(&_productor_cond, nullptr);

        _consumer_wait_num = 0;
        _productor_wait_num = 0;
    }

    bool IsFull()
    {
        return _q.size() == _cap;
    }

    bool IsEmpty()
    {
        return _q.empty();
    }

    void Enqueue(T& data)
    {
        pthread_mutex_lock(&_mutex);
        while(IsFull())
        {
            _productor_wait_num++;
            pthread_cond_wait(&_productor_cond, &_mutex);
            _productor_wait_num--;
        }

        _q.push(data);

        if(_consumer_wait_num > 0)//当有正在等待的消费者时
            pthread_cond_signal(&_consumer_cond);//生产了继续消费
        pthread_mutex_unlock(&_mutex);
    }

    void Pop(T* data)
    {
        pthread_mutex_lock(&_mutex);
        while(IsEmpty())
        {
            _consumer_wait_num++;
            pthread_cond_wait(&_consumer_cond, &_mutex);
            _consumer_wait_num--;
        }

        *data = _q.front();
        _q.pop();

        if(_productor_wait_num > 0)//当有正在阻塞等待的生产者时
            pthread_cond_signal(&_productor_cond);//消费了继续生产
        pthread_mutex_unlock(&_mutex);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_consumer_cond);
        pthread_cond_destroy(&_productor_cond);
    }

private:
    std::queue<T> _q;    //队列存储数据
    int _cap;            //阻塞队列的容量
    pthread_mutex_t _mutex;
    pthread_cond_t _consumer_cond;
    pthread_cond_t _productor_cond;
    int _consumer_wait_num;
    int _productor_wait_num;
};

#endif